import { Client } from 'ssh2';
import { SSHConfig, SSHSession, CommandResult } from '../types';
import { logger } from '../utils/logger';
import { validateSSHConfig, validateCommand } from '../utils/validators';
import { EventEmitter } from 'events';

export class SSHManager extends EventEmitter {
  private connections: Map<string, Client> = new Map();
  private sessions: Map<string, SSHSession> = new Map();

  constructor() {
    super();
  }

  async connect(sessionId: string, config: SSHConfig): Promise<boolean> {
    validateSSHConfig(config);

    return new Promise((resolve, reject) => {
      const client = new Client();

      client.on('ready', () => {
        logger.info(`SSH连接成功: ${config.host}:${config.port}`);

        this.connections.set(sessionId, client);
        this.sessions.set(sessionId, {
          id: sessionId,
          config,
          connected: true,
          lastActivity: new Date()
        });

        this.emit('connected', sessionId);
        resolve(true);
      });

      client.on('error', (err) => {
        logger.error(`SSH连接失败: ${err.message}`);
        this.emit('error', sessionId, err);
        reject(err);
      });

      client.on('close', () => {
        logger.info(`SSH连接关闭: ${config.host}`);
        this.connections.delete(sessionId);
        const session = this.sessions.get(sessionId);
        if (session) {
          session.connected = false;
          this.sessions.set(sessionId, session);
        }
        this.emit('disconnected', sessionId);
      });

      const connectOptions = {
        host: config.host,
        port: config.port,
        username: config.username,
        password: config.password,
        readyTimeout: config.timeout || 30000
      };

      logger.info(`尝试连接SSH: ${config.username}@${config.host}:${config.port}`);
      client.connect(connectOptions);
    });
  }

  async executeCommand(sessionId: string, command: string): Promise<CommandResult> {
    validateCommand(command);

    const client = this.connections.get(sessionId);
    const session = this.sessions.get(sessionId);

    if (!client || !session || !session.connected) {
      throw new Error(`会话 ${sessionId} 未连接`);
    }

    return new Promise((resolve, reject) => {
      logger.info(`执行命令: ${command}`);

      client.exec(command, (err, stream) => {
        if (err) {
          logger.error(`命令执行失败: ${err.message}`);
          reject(err);
          return;
        }

        let stdout = '';
        let stderr = '';

        stream.on('close', (code: number) => {
          const result: CommandResult = {
            success: code === 0,
            stdout: stdout.trim(),
            stderr: stderr.trim(),
            exitCode: code,
            command,
            timestamp: new Date()
          };

          session.lastActivity = new Date();
          this.sessions.set(sessionId, session);

          logger.info(`命令执行完成 [退出码: ${code}]: ${command}`);
          if (result.stderr) {
            logger.warn(`命令错误输出: ${result.stderr}`);
          }

          console.log(`\n📋 命令执行完成 [退出码: ${code}]`);
          resolve(result);
        });

        stream.on('data', (data: Buffer) => {
          const output = data.toString();
          stdout += output;
          // 实时显示标准输出
          process.stdout.write(output);
        });

        stream.stderr.on('data', (data: Buffer) => {
          const output = data.toString();
          stderr += output;
          // 实时显示错误输出，使用红色
          process.stderr.write(`\x1b[31m${output}\x1b[0m`);
        });
      });
    });
  }

  async executeMultipleCommands(sessionId: string, commands: string[]): Promise<CommandResult[]> {
    const results: CommandResult[] = [];

    for (const command of commands) {
      try {
        const result = await this.executeCommand(sessionId, command);
        results.push(result);

        if (!result.success) {
          logger.warn(`命令执行失败，停止后续执行: ${command}`);
          break;
        }
      } catch (error) {
        logger.error(`命令执行异常: ${error}`);
        results.push({
          success: false,
          stdout: '',
          stderr: error instanceof Error ? error.message : String(error),
          exitCode: -1,
          command,
          timestamp: new Date()
        });
        break;
      }
    }

    return results;
  }

  isConnected(sessionId: string): boolean {
    const session = this.sessions.get(sessionId);
    return session ? session.connected : false;
  }

  getSession(sessionId: string): SSHSession | undefined {
    return this.sessions.get(sessionId);
  }

  getAllSessions(): SSHSession[] {
    return Array.from(this.sessions.values());
  }

  async disconnect(sessionId: string): Promise<void> {
    const client = this.connections.get(sessionId);
    if (client) {
      client.end();
      this.connections.delete(sessionId);
    }

    const session = this.sessions.get(sessionId);
    if (session) {
      session.connected = false;
      this.sessions.set(sessionId, session);
    }

    logger.info(`SSH会话已断开: ${sessionId}`);
  }

  async disconnectAll(): Promise<void> {
    const promises = Array.from(this.connections.keys()).map(sessionId =>
      this.disconnect(sessionId)
    );
    await Promise.all(promises);
    logger.info('所有SSH会话已断开');
  }

  cleanupInactiveSessions(timeoutMs: number = 3600000): void {
    const now = new Date();
    const sessionsToCleanup: string[] = [];

    this.sessions.forEach((session, sessionId) => {
      if (!session.connected) return;

      const timeSinceLastActivity = now.getTime() - session.lastActivity.getTime();
      if (timeSinceLastActivity > timeoutMs) {
        sessionsToCleanup.push(sessionId);
      }
    });

    sessionsToCleanup.forEach(sessionId => {
      logger.info(`清理非活跃会话: ${sessionId}`);
      this.disconnect(sessionId);
    });

    if (sessionsToCleanup.length > 0) {
      logger.info(`已清理 ${sessionsToCleanup.length} 个非活跃会话`);
    }
  }
}